Micron Document
🎖️GitЯра🎖️

Commit 33fbb9f7fcab4786c6db51e1773fc1d396de0cf3


Parents : 5fde2d3
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-07-07T13:17:42-05:00
Committer : GitHub <noreply@github.com>
Date : 2026-07-07T18:17:42Z

chore: fix build warnings and migrate deprecated APIs (#6130)

Changes

41 files changed, 104 insertions(+), 60 deletions(-)


Diff

diff --git a/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt b/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt
index ca4984b644..0067032c05 100644
--- a/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt
+++ b/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt
@@ -1046,8 +1046,8 @@ private fun CacheInfoDialog(mapView: MapView, onDismiss: () -> Unit) {
onDismiss = onDismiss,
negativeButton = { TextButton(onClick = { onDismiss() }) { Text(text = stringResource(Res.string.close)) } },
) {
- val capacityMb = (cacheCapacity / (1024 * 1024)).toLong()
- val usageMb = (currentCacheUsage / (1024 * 1024)).toLong()
+ val capacityMb = cacheCapacity / (1024 * 1024)
+ val usageMb = currentCacheUsage / (1024 * 1024)
Text(modifier = Modifier.padding(16.dp), text = stringResource(Res.string.map_cache_info, capacityMb, usageMb))
}
}

diff --git a/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt b/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt
index 61a7c02c72..f3425d7a78 100644
--- a/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt
+++ b/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt
@@ -1230,6 +1230,7 @@ private fun offsetPolyline(
// region --- Map Layers ---
+@OptIn(MapsComposeExperimentalApi::class)
@Composable
private fun MapLayerOverlay(layerItem: MapLayerItem, mapViewModel: MapViewModel) {
val context = LocalContext.current

diff --git a/androidApp/src/google/kotlin/org/meshtastic/app/map/model/CustomTileSource.kt b/androidApp/src/google/kotlin/org/meshtastic/app/map/model/CustomTileSource.kt
index 14db01d4b1..eba9f6e69c 100644
--- a/androidApp/src/google/kotlin/org/meshtastic/app/map/model/CustomTileSource.kt
+++ b/androidApp/src/google/kotlin/org/meshtastic/app/map/model/CustomTileSource.kt
@@ -19,8 +19,7 @@ package org.meshtastic.app.map.model
class CustomTileSource {
companion object {
- fun getTileSource(index: Int) {
- index
- }
+ // No-op stub for the Google flavor (osmdroid tile sources are fdroid-only).
+ fun getTileSource(index: Int) {}
}
}

diff --git a/androidApp/src/test/kotlin/org/meshtastic/app/di/KoinVerificationTest.kt b/androidApp/src/test/kotlin/org/meshtastic/app/di/KoinVerificationTest.kt
index 0aa9d2f414..85396c680c 100644
--- a/androidApp/src/test/kotlin/org/meshtastic/app/di/KoinVerificationTest.kt
+++ b/androidApp/src/test/kotlin/org/meshtastic/app/di/KoinVerificationTest.kt
@@ -38,6 +38,7 @@ import kotlin.test.Test
class KoinVerificationTest {
+ @OptIn(org.koin.core.annotation.KoinExperimentalAPI::class)
@Test
fun verifyKoinConfiguration() {
AppKoinModule()

diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Dokka.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Dokka.kt
index 40477764b8..1438c22364 100644
--- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Dokka.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Dokka.kt
@@ -18,6 +18,7 @@ package org.meshtastic.buildlogic
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.project
import org.jetbrains.dokka.gradle.DokkaExtension
import java.net.URI
@@ -73,5 +74,5 @@ fun Project.configureDokkaAggregation(subprojectPaths: List<String>) {
// Add each subproject as a Dokka dependency using declared paths rather than
// iterating live subproject objects. This avoids cross-project configuration
// access and is compatible with Gradle Isolated Projects.
- subprojectPaths.forEach { path -> dependencies.add("dokka", project(path)) }
+ subprojectPaths.forEach { path -> dependencies.add("dokka", dependencies.project(path)) }
}

diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Kover.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Kover.kt
index c55f6c0fe2..b9ab906c06 100644
--- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Kover.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Kover.kt
@@ -19,6 +19,7 @@ package org.meshtastic.buildlogic
import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.project
fun Project.configureKover() {
val isCi = providers.gradleProperty("ci").map { it.toBoolean() }.getOrElse(false)
@@ -64,5 +65,5 @@ fun Project.configureKover() {
* Isolated Projects. The list should match the modules declared in `settings.gradle.kts`.
*/
fun Project.configureKoverAggregation(subprojectPaths: List<String>) {
- subprojectPaths.forEach { path -> dependencies.add("kover", project(path)) }
+ subprojectPaths.forEach { path -> dependencies.add("kover", dependencies.project(path)) }
}

diff --git a/core/ble/build.gradle.kts b/core/ble/build.gradle.kts
index be45663dd4..fe0525d97f 100644
--- a/core/ble/build.gradle.kts
+++ b/core/ble/build.gradle.kts
@@ -44,7 +44,7 @@ kotlin {
implementation(projects.core.testing)
}
- val androidHostTest by getting {
+ getByName("androidHostTest") {
dependencies {
implementation(projects.core.testing)
implementation(libs.kotlinx.coroutines.test)

diff --git a/core/ble/src/commonMain/kotlin/org/meshtastic/core/ble/KableBleScanner.kt b/core/ble/src/commonMain/kotlin/org/meshtastic/core/ble/KableBleScanner.kt
index c079498ded..c4e53bbbf5 100644
--- a/core/ble/src/commonMain/kotlin/org/meshtastic/core/ble/KableBleScanner.kt
+++ b/core/ble/src/commonMain/kotlin/org/meshtastic/core/ble/KableBleScanner.kt
@@ -46,6 +46,10 @@ internal fun resolveKableScanFilter(serviceUuid: Uuid?, address: String?): Kable
else -> KableScanFilter.None
}
+// Kable's Advertisement.identifier is an expect typealias: String on Android/JVM/JS but Uuid on Apple.
+// toString() looks redundant when compiling the Android/JVM view (hence the warning) but is required to
+// normalize the Apple Uuid to the String this result carries, so it must stay.
+@Suppress("REDUNDANT_CALL_OF_CONVERSION_METHOD")
private fun Advertisement.toScanResult(): KableScanResult =
KableScanResult(identifier = identifier.toString(), name = name, advertisement = this)

diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts
index a3d273839f..3036e7b31e 100644
--- a/core/data/build.gradle.kts
+++ b/core/data/build.gradle.kts
@@ -49,7 +49,7 @@ kotlin {
}
// Room / SQLite runtime shared between Android and Desktop JVM targets
- val jvmAndroidMain by getting {
+ getByName("jvmAndroidMain") {
dependencies {
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.paging)
@@ -67,7 +67,7 @@ kotlin {
implementation(libs.kotlinx.coroutines.test)
}
- val androidHostTest by getting {
+ getByName("androidHostTest") {
dependencies {
// JVM variant provides the host-platform native for BundledSQLiteDriver (same as core:database)
runtimeOnly("androidx.sqlite:sqlite-bundled-jvm:2.7.0")

diff --git a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/AiFunctionProviderImpl.kt b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/AiFunctionProviderImpl.kt
index f1b5a37fc9..549a858405 100644
--- a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/AiFunctionProviderImpl.kt
+++ b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/AiFunctionProviderImpl.kt
@@ -270,7 +270,7 @@ class AiFunctionProviderImpl(
when {
totalCount == 0 -> 0
onlineCount == 0 -> HEALTH_SCORE_DEGRADED
- else -> (HEALTH_SCORE_BASE + (HEALTH_SCORE_ONLINE_RATIO * onlineCount) / totalCount).toInt()
+ else -> HEALTH_SCORE_BASE + (HEALTH_SCORE_ONLINE_RATIO * onlineCount) / totalCount
}
// Find most recent packet: max lastHeard across all nodes (convert seconds to ms)

diff --git a/core/database/build.gradle.kts b/core/database/build.gradle.kts
index 5d779655bf..4dd710a32c 100644
--- a/core/database/build.gradle.kts
+++ b/core/database/build.gradle.kts
@@ -50,7 +50,7 @@ kotlin {
implementation(libs.androidx.room.testing)
}
- val androidHostTest by getting {
+ getByName("androidHostTest") {
dependencies {
implementation(libs.androidx.sqlite.bundled)
// JVM variant provides the host-platform native for BundledSQLiteDriver
@@ -60,7 +60,7 @@ kotlin {
implementation(libs.junit)
}
}
- val androidDeviceTest by getting {
+ getByName("androidDeviceTest") {
dependencies {
implementation(libs.androidx.room.testing)
implementation(libs.androidx.test.ext.junit)

diff --git a/core/konsist/build.gradle.kts b/core/konsist/build.gradle.kts
index 1cbc77d8d7..8739598bcf 100644
--- a/core/konsist/build.gradle.kts
+++ b/core/konsist/build.gradle.kts
@@ -28,7 +28,7 @@ kotlin {
android { withHostTest {} }
sourceSets {
- val jvmTest by getting {
+ getByName("jvmTest") {
dependencies {
implementation(libs.konsist)
implementation(libs.junit)

diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts
index 9ab0d4c961..a29782e567 100644
--- a/core/model/build.gradle.kts
+++ b/core/model/build.gradle.kts
@@ -60,7 +60,7 @@ kotlin {
api(libs.androidx.annotation)
api(libs.androidx.core.ktx)
}
- val androidDeviceTest by getting {
+ getByName("androidDeviceTest") {
dependencies {
implementation(libs.androidx.test.ext.junit)
implementation(libs.androidx.test.runner)

diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts
index c9baaee850..f8ab2ad6da 100644
--- a/core/network/build.gradle.kts
+++ b/core/network/build.gradle.kts
@@ -55,7 +55,7 @@ kotlin {
implementation(libs.jetbrains.lifecycle.runtime)
}
- val jvmMain by getting {
+ getByName("jvmMain") {
dependencies {
implementation(libs.ktor.client.java)
implementation(libs.jserialcomm)

diff --git a/core/network/src/commonMain/kotlin/org/meshtastic/core/network/repository/MQTTRepositoryImpl.kt b/core/network/src/commonMain/kotlin/org/meshtastic/core/network/repository/MQTTRepositoryImpl.kt
index 9f76507817..89e214a505 100644
--- a/core/network/src/commonMain/kotlin/org/meshtastic/core/network/repository/MQTTRepositoryImpl.kt
+++ b/core/network/src/commonMain/kotlin/org/meshtastic/core/network/repository/MQTTRepositoryImpl.kt
@@ -114,6 +114,9 @@ class MQTTRepositoryImpl(
scope.launch { safeCatching { c?.close() }.onFailure { e -> Logger.w(e) { "MQTT clean disconnect failed" } } }
}
+ // json_enabled is deprecated in the protobuf schema but remains the only way to toggle MQTT JSON
+ // publish/consume, so we must keep reading it until the firmware/proto provides a replacement.
+ @Suppress("DEPRECATION")
@OptIn(ExperimentalSerializationApi::class)
override val proxyMessageFlow: Flow<MqttClientProxyMessage> = callbackFlow {
// Append a per-connection random id. myId identifies the *node* (and is null →

diff --git a/core/service/build.gradle.kts b/core/service/build.gradle.kts
index d2fea9dde3..fe74edb4c5 100644
--- a/core/service/build.gradle.kts
+++ b/core/service/build.gradle.kts
@@ -52,7 +52,7 @@ kotlin {
implementation(libs.koin.androidx.workmanager)
}
- val androidHostTest by getting {
+ getByName("androidHostTest") {
dependencies {
implementation(projects.core.testing)
implementation(libs.androidx.test.ext.junit)

diff --git a/core/service/src/androidMain/kotlin/org/meshtastic/core/service/LockdownPassphraseStoreImpl.kt b/core/service/src/androidMain/kotlin/org/meshtastic/core/service/LockdownPassphraseStoreImpl.kt
index 0c908ae2cd..7711138542 100644
--- a/core/service/src/androidMain/kotlin/org/meshtastic/core/service/LockdownPassphraseStoreImpl.kt
+++ b/core/service/src/androidMain/kotlin/org/meshtastic/core/service/LockdownPassphraseStoreImpl.kt
@@ -35,7 +35,10 @@ import org.meshtastic.core.repository.StoredPassphrase
@Single(binds = [LockdownPassphraseStore::class])
class LockdownPassphraseStoreImpl(app: Application) : LockdownPassphraseStore {
- @Suppress("TooGenericExceptionCaught")
+ // androidx.security.crypto (MasterKey / EncryptedSharedPreferences) is deprecated by Google with no
+ // drop-in AndroidX replacement yet. Migrating encrypted storage is a separate, security-sensitive
+ // effort; suppress until a stable replacement (e.g. Tink) is adopted.
+ @Suppress("TooGenericExceptionCaught", "DEPRECATION")
private val prefs: SharedPreferences? by lazy {
try {
val masterKey = MasterKey.Builder(app).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()

diff --git a/core/service/src/androidMain/kotlin/org/meshtastic/core/service/SecurityKeyBackupStoreImpl.kt b/core/service/src/androidMain/kotlin/org/meshtastic/core/service/SecurityKeyBackupStoreImpl.kt
index 5f94b7b3b3..1f12c25bd1 100644
--- a/core/service/src/androidMain/kotlin/org/meshtastic/core/service/SecurityKeyBackupStoreImpl.kt
+++ b/core/service/src/androidMain/kotlin/org/meshtastic/core/service/SecurityKeyBackupStoreImpl.kt
@@ -34,7 +34,10 @@ import org.meshtastic.core.repository.StoredSecurityKeys
@Single(binds = [SecurityKeyBackupStore::class])
class SecurityKeyBackupStoreImpl(app: Application) : SecurityKeyBackupStore {
- @Suppress("TooGenericExceptionCaught")
+ // androidx.security.crypto (MasterKey / EncryptedSharedPreferences) is deprecated by Google with no
+ // drop-in AndroidX replacement yet. Migrating encrypted storage is a separate, security-sensitive
+ // effort; suppress until a stable replacement (e.g. Tink) is adopted.
+ @Suppress("TooGenericExceptionCaught", "DEPRECATION")
private val prefs: SharedPreferences? by lazy {
try {
val masterKey = MasterKey.Builder(app).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()

diff --git a/core/service/src/commonMain/kotlin/org/meshtastic/core/service/SharedRadioInterfaceService.kt b/core/service/src/commonMain/kotlin/org/meshtastic/core/service/SharedRadioInterfaceService.kt
index 0550bf380d..4087d7ef3d 100644
--- a/core/service/src/commonMain/kotlin/org/meshtastic/core/service/SharedRadioInterfaceService.kt
+++ b/core/service/src/commonMain/kotlin/org/meshtastic/core/service/SharedRadioInterfaceService.kt
@@ -717,7 +717,7 @@ class SharedRadioInterfaceService(
// would replay stale bytes ahead of the next session's firmware handshake, since the channel
// outlives the orchestrator's per-start scope.
@Suppress("EmptyWhileBlock", "ControlFlowWithEmptyBody")
- while (_receivedData.tryReceive().isSuccess) Unit
+ while (_receivedData.tryReceive().isSuccess) {}
}
override fun onConnect() {

diff --git a/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/CoTXmlParser.kt b/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/CoTXmlParser.kt
index 4993bf301e..e98dde4a13 100644
--- a/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/CoTXmlParser.kt
+++ b/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/CoTXmlParser.kt
@@ -23,11 +23,17 @@ import nl.adaptivity.xmlutil.serialization.XML
import kotlin.time.Clock
import kotlin.time.Instant
-private val xmlParser = XML {
- // xmlutil 1.0.0 moved repairNamespaces from the policy builder to the top-level XML config.
- repairNamespaces = false
- defaultPolicy { ignoreUnknownChildren() }
-}
+// XML.compat preserves xmlutil's pre-1.0 serialization defaults. The non-deprecated 1.0 builders
+// (XML.recommended/XML.V1) intentionally change serialization defaults, which would alter the CoT XML
+// wire format we exchange with ATAK/TAK servers. Staying on the compat policy until that migration can
+// be validated against real TAK interop; suppress the soft-deprecation on the factory itself.
+@Suppress("DEPRECATION")
+private val xmlParser =
+ XML.compat {
+ // xmlutil 1.0.0 moved repairNamespaces from the policy builder to the top-level XML config.
+ repairNamespaces = false
+ defaultPolicy { ignoreUnknownChildren() }
+ }
class CoTXmlParser(private val xml: String) {
fun parse(): Result<CoTMessage> = try {

diff --git a/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/TAKDataPackageGenerator.kt b/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/TAKDataPackageGenerator.kt
index 1b5a86d390..ad2ab988a8 100644
--- a/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/TAKDataPackageGenerator.kt
+++ b/core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/TAKDataPackageGenerator.kt
@@ -46,10 +46,16 @@ object TAKDataPackageGenerator {
private const val CLIENT_P12_FILE_NAME = "client.p12"
private const val PACKAGE_NAME = "Meshtastic_TAK_Server"
- private val xmlSerializer = XML {
- xmlDeclMode = XmlDeclMode.Charset
- indentString = " "
- }
+ // XML.compat preserves xmlutil's pre-1.0 serialization defaults. The non-deprecated 1.0 builders
+ // (XML.recommended/XML.V1) intentionally change serialization defaults, which would alter the CoT
+ // XML wire format consumed by ATAK/TAK servers. Staying on the compat policy until that migration
+ // can be validated against real TAK interop; suppress the soft-deprecation on the factory itself.
+ @Suppress("DEPRECATION")
+ private val xmlSerializer =
+ XML.compat {
+ xmlDeclMode = XmlDeclMode.Charset
+ indentString = " "
+ }
/**
* Platform-specific hook for reading the bundled TLS certificate bytes. Default implementation lives in

diff --git a/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeRadioInterfaceService.kt b/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeRadioInterfaceService.kt
index 21cf6c63fa..048ec37b00 100644
--- a/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeRadioInterfaceService.kt
+++ b/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeRadioInterfaceService.kt
@@ -109,7 +109,7 @@ class FakeRadioInterfaceService(override val serviceScope: CoroutineScope = Main
override fun resetReceivedBuffer() {
@Suppress("EmptyWhileBlock", "ControlFlowWithEmptyBody")
- while (_receivedData.tryReceive().isSuccess) Unit
+ while (_receivedData.tryReceive().isSuccess) {}
}
// --- Helper methods for testing ---

diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts
index c6e248638c..4c55e4f6c8 100644
--- a/core/ui/build.gradle.kts
+++ b/core/ui/build.gradle.kts
@@ -64,7 +64,7 @@ kotlin {
implementation(libs.jetbrains.lifecycle.runtime.compose)
}
- val jvmAndroidMain by getting { dependencies { implementation(libs.compose.multiplatform.ui.tooling) } }
+ getByName("jvmAndroidMain") { dependencies { implementation(libs.compose.multiplatform.ui.tooling) } }
androidMain.dependencies { implementation(libs.androidx.activity.compose) }

diff --git a/core/ui/src/androidMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt b/core/ui/src/androidMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt
index 1afcf0d6ab..d081cf802a 100644
--- a/core/ui/src/androidMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt
+++ b/core/ui/src/androidMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt
@@ -332,6 +332,10 @@ actual fun isWifiUnavailable(): Boolean {
* the transport reduction can delegate to the platform-agnostic [anyNetworkScanTransportAvailable] helper (which is
* unit-tested in `commonTest`).
*/
+// ConnectivityManager.allNetworks is deprecated (API 31+) in favor of NetworkCallback-based discovery,
+// but a synchronous snapshot of active networks is exactly what this transport probe needs. Suppress
+// until a callback-based rewrite is warranted.
+@Suppress("DEPRECATION")
private fun ConnectivityManager.hasLocalNetwork(): Boolean {
val transports =
allNetworks.mapNotNull { network ->

diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt
index c3e1e68f7d..a4259f6fb3 100644
--- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt
+++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt
@@ -52,10 +52,10 @@ internal class EmojiPickerViewModel(
emojiRepository.preload()
_isLoaded.value = true
} catch (e: MissingResourceException) {
- Logger.e("EmojiPickerViewModel", e) { "Failed to load emoji data" }
+ Logger.e(tag = "EmojiPickerViewModel", throwable = e) { "Failed to load emoji data" }
_loadError.value = true
} catch (e: IllegalStateException) {
- Logger.e("EmojiPickerViewModel", e) { "Failed to load emoji data" }
+ Logger.e(tag = "EmojiPickerViewModel", throwable = e) { "Failed to load emoji data" }
_loadError.value = true
}
}

diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/ProtoExtensions.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/ProtoExtensions.kt
index 12ea29288c..f4d239dacb 100644
--- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/ProtoExtensions.kt
+++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/ProtoExtensions.kt
@@ -195,7 +195,7 @@ fun normalizeReplacementSettings(
}
/** True when a [ChannelSettings] carries no name and no PSK — a placeholder, not an intended channel. */
-private fun ChannelSettings.isPlaceholder(): Boolean = name.isNullOrBlank() && (psk == null || psk.size == 0)
+private fun ChannelSettings.isPlaceholder(): Boolean = name.isNullOrBlank() && psk.size == 0
/**
* Applies an imported [ChannelSet] as an authoritative replacement to the radio and local cache.

diff --git a/core/ui/src/iosMain/kotlin/org/meshtastic/core/ui/util/NoopStubs.kt b/core/ui/src/iosMain/kotlin/org/meshtastic/core/ui/util/NoopStubs.kt
index 296852973a..f2203eb3d1 100644
--- a/core/ui/src/iosMain/kotlin/org/meshtastic/core/ui/util/NoopStubs.kt
+++ b/core/ui/src/iosMain/kotlin/org/meshtastic/core/ui/util/NoopStubs.kt
@@ -46,7 +46,7 @@ actual fun rememberSaveFileLauncher(
@Composable
actual fun rememberOpenFileLauncher(onUriReceived: (CommonUri?) -> Unit): (mimeType: String) -> Unit = { _ -> }
-@Composable actual fun rememberReadTextFromUri(): suspend (CommonUri, Int) -> String? = { _, _ -> null }
+@Composable actual fun rememberReadTextFromUri(): suspend (uri: CommonUri, maxChars: Int) -> String? = { _, _ -> null }
@Composable actual fun KeepScreenOn(enabled: Boolean) {}

diff --git a/core/ui/src/jvmMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt b/core/ui/src/jvmMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt
index b3fa848157..846a8e2763 100644
--- a/core/ui/src/jvmMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt
+++ b/core/ui/src/jvmMain/kotlin/org/meshtastic/core/ui/util/PlatformUtils.kt
@@ -76,7 +76,9 @@ actual fun rememberSaveFileLauncher(
/** JVM — Opens a native file dialog to pick a file. */
@Composable
actual fun rememberOpenFileLauncher(onUriReceived: (CommonUri?) -> Unit): (mimeType: String) -> Unit = { _ ->
- val dialog = FileDialog(null as? Frame, "Open File", FileDialog.LOAD)
+ // Explicit Frame? local disambiguates the FileDialog(Frame, ...) overload from FileDialog(Dialog, ...)
+ val parentFrame: Frame? = null
+ val dialog = FileDialog(parentFrame, "Open File", FileDialog.LOAD)
dialog.isVisible = true
val file = dialog.file
val dir = dialog.directory

diff --git a/desktopApp/src/main/kotlin/org/meshtastic/desktop/stub/NoopStubs.kt b/desktopApp/src/main/kotlin/org/meshtastic/desktop/stub/NoopStubs.kt
index 898c6e2925..c1490675c6 100644
--- a/desktopApp/src/main/kotlin/org/meshtastic/desktop/stub/NoopStubs.kt
+++ b/desktopApp/src/main/kotlin/org/meshtastic/desktop/stub/NoopStubs.kt
@@ -25,7 +25,6 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.emptyFlow
import org.meshtastic.core.model.ConnectionState
import org.meshtastic.core.model.DeviceType
@@ -72,8 +71,8 @@ class NoopRadioInterfaceService : RadioInterfaceService {
override fun isMockTransport(): Boolean = false
override val receivedData = MutableSharedFlow<ByteArray>()
- override val meshActivity: Flow<MeshActivity> = MutableSharedFlow<MeshActivity>().asFlow()
- override val connectionError: Flow<String> = MutableSharedFlow<String>().asFlow()
+ override val meshActivity: Flow<MeshActivity> = MutableSharedFlow<MeshActivity>()
+ override val connectionError: Flow<String> = MutableSharedFlow<String>()
override fun sendToRadio(bytes: ByteArray) {
logWarn("NoopRadioInterfaceService.sendToRadio(${bytes.size} bytes)")

diff --git a/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt b/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt
index 650f098c6f..b79780ed9c 100644
--- a/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt
+++ b/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt
@@ -257,12 +257,15 @@ class HomeScreen(
}
}
- return ConversationItem.Builder()
- .setId(conversation.contactKey)
- .setTitle(CarText.create(conversation.displayName))
- .setMessages(messages)
- .setSelf(selfPerson)
- .setConversationCallback(callback)
+ // car-app 1.7 deprecated the no-arg Builder + individual setters in favor of the
+ // required-args constructor (id, title, self, messages, conversationCallback).
+ return ConversationItem.Builder(
+ conversation.contactKey,
+ CarText.create(conversation.displayName),
+ selfPerson,
+ messages,
+ callback,
+ )
.setGroupConversation(conversation.contactKey.contains(NodeAddress.ID_BROADCAST))
.build()
}

diff --git a/feature/connections/build.gradle.kts b/feature/connections/build.gradle.kts
index 97fd9f284f..bbab106fbc 100644
--- a/feature/connections/build.gradle.kts
+++ b/feature/connections/build.gradle.kts
@@ -42,7 +42,7 @@ kotlin {
androidMain.dependencies { implementation(libs.usb.serial.android) }
- val androidHostTest by getting {
+ getByName("androidHostTest") {
dependencies {
implementation(projects.core.testing)
implementation(libs.kotlinx.coroutines.test)

diff --git a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt
index b556e6011d..02f3dbffa0 100644
--- a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt
+++ b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt
@@ -34,12 +34,12 @@ import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
@@ -361,7 +361,7 @@ private fun DwellTimePicker(
readOnly = true,
enabled = enabled,
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
- modifier = Modifier.fillMaxWidth().menuAnchor(MenuAnchorType.PrimaryNotEditable),
+ modifier = Modifier.fillMaxWidth().menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable),
)
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DWELL_OPTIONS.forEach { minutes ->

diff --git a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/component/MeshBeaconInvitationCard.kt b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/component/MeshBeaconInvitationCard.kt
index 23ae7ff3e9..f593e5a8e1 100644
--- a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/component/MeshBeaconInvitationCard.kt
+++ b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/component/MeshBeaconInvitationCard.kt
@@ -85,7 +85,7 @@ internal fun MeshBeaconInvitationCard(
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
- if (region != null && region != RegionCode.UNSET) {
+ if (region != RegionCode.UNSET) {
Text(
text = stringResource(Res.string.mesh_beacon_offer_region, region.name),
style = MaterialTheme.typography.labelMedium,

diff --git a/feature/docs/build.gradle.kts b/feature/docs/build.gradle.kts
index b39cc766ed..948ddef73d 100644
--- a/feature/docs/build.gradle.kts
+++ b/feature/docs/build.gradle.kts
@@ -57,8 +57,8 @@ kotlin {
*
* This task runs automatically before resource generation tasks.
*/
-val syncDocsToComposeResources by
- tasks.registering(Sync::class) {
+val syncDocsToComposeResources =
+ tasks.register<Sync>("syncDocsToComposeResources") {
description = "Syncs docs/en/ markdown source into composeResources for in-app bundling"
group = "docs"
@@ -102,8 +102,8 @@ tasks
// clean, or commit deliberately when refreshing the docs/Jekyll image set. Add a CI staleness gate
// if drift becomes a problem.
-val syncTranslatedDocsToComposeResources by
- tasks.registering(Copy::class) {
+val syncTranslatedDocsToComposeResources =
+ tasks.register<Copy>("syncTranslatedDocsToComposeResources") {
description = "Syncs Crowdin-translated docs into locale-qualified composeResources"
group = "docs"

diff --git a/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt b/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt
index 5b2bdfef8d..4ff36840da 100644
--- a/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt
+++ b/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt
@@ -145,7 +145,6 @@ import org.meshtastic.core.ui.icon.Dangerous
import org.meshtastic.core.ui.icon.Folder
import org.meshtastic.core.ui.icon.MeshtasticIcons
import org.meshtastic.core.ui.icon.Refresh
-import org.meshtastic.core.ui.icon.SystemUpdate
import org.meshtastic.core.ui.icon.Usb
import org.meshtastic.core.ui.icon.Warning
import org.meshtastic.core.ui.icon.Wifi
@@ -462,7 +461,6 @@ private fun ReadyState(
FirmwareUpdateMethod.Ble -> MeshtasticIcons.Bluetooth
FirmwareUpdateMethod.Usb -> MeshtasticIcons.Usb
FirmwareUpdateMethod.Wifi -> MeshtasticIcons.Wifi
- else -> MeshtasticIcons.SystemUpdate
},
contentDescription = null,
)

diff --git a/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateViewModel.kt b/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateViewModel.kt
index 96b7af668f..92dbd776f8 100644
--- a/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateViewModel.kt
+++ b/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateViewModel.kt
@@ -21,6 +21,7 @@ import androidx.lifecycle.viewModelScope
import co.touchlab.kermit.Logger
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.delay
@@ -134,6 +135,7 @@ class FirmwareUpdateViewModel(
}
}
+ @OptIn(DelicateCoroutinesApi::class)
override fun onCleared() {
super.onCleared()
// viewModelScope is already cancelled when onCleared() runs, so launch cleanup on the

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/domain/usecase/CommonGetNodeDetailsUseCase.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/domain/usecase/CommonGetNodeDetailsUseCase.kt
index c588259302..f449704353 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/domain/usecase/CommonGetNodeDetailsUseCase.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/domain/usecase/CommonGetNodeDetailsUseCase.kt
@@ -176,8 +176,13 @@ constructor(
val logs = args[LOGS_INDEX] as LogsGroup
val identity = args[IDENTITY_INDEX] as IdentityGroup
val metadata = args[METADATA_INDEX] as MetadataGroup
+
+ @Suppress("UNCHECKED_CAST")
val requests = args[REQUESTS_INDEX] as Pair<List<MeshLog>, List<MeshLog>>
- val (hw, deviceLinks) = args[HARDWARE_INDEX] as Pair<DeviceHardware?, List<DeviceLink>>
+
+ @Suppress("UNCHECKED_CAST")
+ val hardwareAndLinks = args[HARDWARE_INDEX] as Pair<DeviceHardware?, List<DeviceLink>>
+ val (hw, deviceLinks) = hardwareAndLinks
val (trReqs, niReqs) = requests
val isLocal = node.num == identity.ourNode?.num

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt
index b9ce30fa99..547bd53402 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt
@@ -49,7 +49,7 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.patrykandpatrick.vico.compose.cartesian.VicoScrollState
import com.patrykandpatrick.vico.compose.cartesian.axis.Axis
-import com.patrykandpatrick.vico.compose.cartesian.data.lineSeries
+import com.patrykandpatrick.vico.compose.cartesian.data.lineModel
import com.patrykandpatrick.vico.compose.cartesian.layer.LineCartesianLayer
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource
@@ -223,7 +223,7 @@ private fun AirQualityChart(
activeMetrics.forEachIndexed { index, metric ->
val metricData = metricDataSets[index]
if (metricData.isNotEmpty()) {
- lineSeries {
+ lineModel {
series(x = metricData.map { it.time }, y = metricData.map { metric.getValue(it) ?: 0f })
}
}

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt
index 99a5e7869d..87df574c2f 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt
@@ -133,7 +133,7 @@ fun GenericMetricChart(
bottomAxis = bottomAxis,
marker = marker,
markerVisibilityListener = markerVisibilityListener,
- persistentMarkers = { _ -> if (selectedX != null && marker != null) marker at selectedX else null },
+ persistentMarkers = { _ -> if (selectedX != null && marker != null) marker at selectedX },
fadingEdges = rememberFadingEdges(),
decorations = decorations,
// Telemetry timestamps arrive at irregular intervals. Without an explicit

diff --git a/feature/settings/detekt-baseline.xml b/feature/settings/detekt-baseline.xml
index 7a54174fc0..d1ae234f8e 100644
--- a/feature/settings/detekt-baseline.xml
+++ b/feature/settings/detekt-baseline.xml
@@ -58,7 +58,7 @@
<ID>ModifierMissing:ExternalNotificationConfigScreen.android.kt:@Suppress("TooGenericExceptionCaught") @Composable actual fun RingtoneTrailingIcon</ID>
<ID>ModifierMissing:FilterSettingsScreen.kt:@Composable fun FilterSettingsScreen</ID>
<ID>ModifierMissing:LoRaConfigItemList.kt:@Composable fun LoRaConfigScreen</ID>
- <ID>ModifierMissing:MQTTConfigItemList.kt:@Composable fun MQTTConfigScreen</ID>
+ <ID>ModifierMissing:MQTTConfigItemList.kt:@Suppress("DEPRECATION") @Composable fun MQTTConfigScreen</ID>
<ID>ModifierMissing:MapReportingPreference.kt:@Suppress("LongMethod") @Composable fun MapReportingPreference</ID>
<ID>ModifierMissing:ModuleConfigurationScreen.kt:@Composable fun ModuleConfigurationScreen</ID>
<ID>ModifierMissing:NeighborInfoConfigItemList.kt:@Composable fun NeighborInfoConfigScreen</ID>

diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/MQTTConfigItemList.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/MQTTConfigItemList.kt
index 80eccdef5c..8a9b086a06 100644
--- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/MQTTConfigItemList.kt
+++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/MQTTConfigItemList.kt
@@ -89,6 +89,9 @@ import org.meshtastic.core.ui.component.TitledCard
import org.meshtastic.feature.settings.radio.RadioConfigViewModel
import org.meshtastic.proto.ModuleConfig
+// json_enabled is deprecated in the protobuf schema but remains the only toggle for MQTT JSON
+// publish/consume, so the settings UI must keep exposing it until the proto provides a replacement.
+@Suppress("DEPRECATION")
@Composable
fun MQTTConfigScreen(viewModel: RadioConfigViewModel, onBack: () -> Unit) {
val state by viewModel.radioConfigState.collectAsStateWithLifecycle()

Served by rngit 1.5.2 - Generated in 0.55s